import React from 'react';
import { TreeSelect, Spin } from 'antd';
import { connect } from "dva";
import { isEmpty } from "@cbd/utils";
import Zcon from '@cbd/icon';

const { TreeNode } = TreeSelect;

@connect(({
  usertreeSelect,
  loading,
}) => ({
  loading,
  usertreeSelectStore: usertreeSelect,
}))
class CustomTreeSelectField extends React.Component {
  static defaultProps = {
    type: "STA", // 默认人员选择
  }

  static getDerivedStateFromProps(nextProps) {
    // Should be a controlled component.
    if ('value' in nextProps) {
      return {
        // value: (nextProps.value || []),
        selectedKeys: (nextProps.value || []),
      };
    }
    return null;
  }

  constructor(props) {
    super(props);
    const value = props.value || [];
    this.state = {
      selectedKeys: value,
      treeData: [],
    };
    this.selectData = [];
    this.loadedKeys = [];
    this.selectedKeysInvert = [];
  }

  componentDidMount() {
  }

  componentWillUnmount() { }

  getRootOrg = () => {
    const { dispatch } = this.props;
    if (!dispatch) return;
    this.isloading = true;
    dispatch({
      type: 'usertreeSelect/getRootOrg', payload: {},
    }).then(({ errCode, datas }) => {
      this.isloading = false;
      if (errCode !== 0) {
        return;
      }
      const newDatas = Array.isArray(datas) ? datas : [datas];
      this.loadedKeys = this.loadedKeys.concat(newDatas);
      this.setState({ treeData: newDatas });
    });
  }

  getCandidateGroups = () => {
    const { dispatch, appId } = this.props;
    if (!dispatch) return;
    dispatch({
      type: "FlowChart/getCandidateGroups", payload: appId ? { appId } : {},
    }).then(({ errCode, datas = [] }) => {
      if (errCode !== 0) {
        return;
      }
      const newData = datas.map(sitem => {
        sitem.isLeaf = true;
        sitem.roleCode = sitem.roleCode || sitem.groupId;
        sitem.roleName = sitem.roleName || sitem.groupName;
        return sitem;
      });
      this.loadedKeys = this.loadedKeys.concat(newData);
      this.setState({ treeData: newData });
      this.setTreeSelectData(this.selectedKeysInvert, this.selectData);
    });
  }

  setTreeSelectData = (selectedKeys = [], selectData = []) => {
    const { type } = this.props;
    this.selectData = selectData;
    this.selectedKeysInvert = selectedKeys; // 需要反显的数据
    let newSelectedKeys = [];
    if (type === 'ORG') {
      newSelectedKeys = selectedKeys.filter(item => this.loadedKeys.some(citem => citem.code === item));
    } else if (type === 'STA') {
      newSelectedKeys = selectedKeys.filter(item => this.loadedKeys.some(citem => citem.code === item));
    } else if (type === 'ROL') {
      newSelectedKeys = selectedKeys.filter(item => this.loadedKeys.some(citem => citem.roleCode === item));
    }
    this.setState({ selectedKeys: newSelectedKeys });
  }

  handleLoadData = treeNode => new Promise((resolve) => {
    const { dispatch, type, multiple } = this.props;
    const isJustLoadOrg = type === "ORG";
    const { treeData, selectedKeys } = this.state;
    if (treeNode.props.children) {
      resolve();
      return;
    }
    const orgCode = treeNode.props.dataRef.code;
    const orgName = treeNode.props.dataRef.displayName;
    dispatch({
      type: 'usertreeSelect/getChildren', isJustLoadOrg, payload: { pageNo: 1, pageSize: 1000, orgCode, orgName },
    }).then(({ datas }) => {
      if (datas && datas.length > 0) {
        treeNode.props.dataRef.children = datas;
        /*
        // 反显处理
        const loadedSelectedKeys = this.selectedKeysInvert.filter(item => {
          return datas.some(citem => citem.code === item)
        });
        const newKeys = [...selectedKeys, ...loadedSelectedKeys]
        this.loadedKeys = this.loadedKeys.concat(datas);
        this.setState({
          treeData: [...treeData],
          selectedKeys: newKeys,
        });
        resolve();
        */
        // 反显处理
        if (multiple) {
          let loadedSelectedKeys = [];
          if (isJustLoadOrg) {
            loadedSelectedKeys = this.selectedKeysInvert.filter(item => {
              return datas.some(citem => citem.code === item)
            });
          } else {
            loadedSelectedKeys = this.selectedKeysInvert.filter(item => {
              return datas.some(citem => citem.code === item)
            });
          }
          const newKeys = [...selectedKeys, ...loadedSelectedKeys]
          this.loadedKeys = this.loadedKeys.concat(datas);
          this.setState({
            treeData: [...treeData],
            selectedKeys: newKeys,
          });
        } else {
          this.setState({ treeData: [...treeData] });
        }
        resolve();
      }
      resolve();
    });
  });

  renderTreeNodes = data => data.map((item) => {
    const { multiple = false, type } = this.props;
    const isJustLoadOrg = type === "ORG";
    const { code, displayName, isLeaf = false, children } = item;
    const key = code;
    const title = displayName;
    const treeNodeProps = {};
    let selectable = true;
    if (!multiple && !isLeaf && !isJustLoadOrg) {
      selectable = false;
    }
    if (multiple) {
      treeNodeProps.disableCheckbox = !isLeaf;
    } else {
      treeNodeProps.selectable = selectable;
    }
    if (children) {
      return (
        <TreeNode {...treeNodeProps} title={title} key={key} dataRef={item}>
          {this.renderTreeNodes(children)}
        </TreeNode>
      );
    }

    return (
      <TreeNode
        {...treeNodeProps}
        title={title}
        key={key}
        dataRef={item}
        isLeaf={isLeaf}
        value={key}
      />
    );
  });

  renderRolTreeNodes = data => data.map((item) => {
    const { multiple } = this.props;
    const { roleName, roleCode, isLeaf = false, children } = item;
    const treeNodeProps = {};
    let selectable = true;
    if (!multiple && !isLeaf) {
      selectable = false;
    }
    if (multiple) {
      treeNodeProps.disableCheckbox = !isLeaf;
    } else {
      treeNodeProps.selectable = selectable;
    }
    if (children) {
      return (
        <TreeNode {...treeNodeProps} title={roleName} key={roleCode} dataRef={item}>
          {this.renderRolTreeNodes(children)}
        </TreeNode>
      );
    }
    return (
      <TreeNode
        {...treeNodeProps}
        title={roleName}
        key={roleCode}
        dataRef={item}
        isLeaf={item.isLeaf || false}
        value={roleCode}
      />
    );
  });

  onChange = (value) => {
    this.setState({ selectedKeys: value });
    this.triggerChange(value);
  }

  triggerChange = (changedValue) => {
    // Should provide an event to pass value to Form.
    const { onChange } = this.props;
    if (onChange) {
      onChange(changedValue);
    }
  }

  handleClick = () => {
    const { treeData } = this.state;
    const { itemProps, type } = this.props;
    const { disabled } = itemProps || {};
    if (disabled) return;
    if (!this.isloading && isEmpty(treeData)) {
      if (type === 'ROL') {
        this.getCandidateGroups();
        return;
      }
      this.getRootOrg();
    }
  }

  render() {
    const { selectedKeys, treeData } = this.state;
    const { itemProps, multiple = false, loading: { effects }, type, placeholder } = this.props;
    const { disabled } = itemProps || {};
    const iconType = multiple ? 'usergroup-add' : 'user-add';
    const rootLoading = effects['usertreeSelect/getRootOrg'] ||
      effects["FlowChart/getCandidateGroups"];
    const proObj = {};
    if (!multiple) proObj.labelInValue = true;
    return (
      <TreeSelect
        // style={{ width: 300 }}
        showSearch
        treeNodeFilterProp="title"
        style={{ minWidth: 118 }}
        value={selectedKeys}
        dropdownStyle={{ minHeight: 100, maxHeight: 320, overflow: 'auto' }}
        loadData={this.handleLoadData}
        placeholder={placeholder}
        onChange={this.onChange}
        onClick={this.handleClick}
        multiple={multiple}
        treeCheckable={multiple}
        treeCheckStrictly={multiple}
        disabled={disabled}
        suffixIcon={<Zcon type={iconType} />}
        notFoundContent={rootLoading ? <Spin spinning={rootLoading} /> : null}
        {...proObj}
      >
        {/* this.renderTreeNodes(treeData) */}
        {type === 'ROL' ? this.renderRolTreeNodes(treeData) : this.renderTreeNodes(treeData)}
      </TreeSelect>
    );
  }
}
export default CustomTreeSelectField;
